# Write playlists in various flavors.

import sys
import os
import utils

# TODO add tests

class WriterFactory:
    def __init__(self):
        self._writers = []

    # For a list of (type, kwargs), return a matching list of actual instances.
    def get_writers(self, type_and_kwargs_list):
        writers = []
        for type_and_kwargs in type_and_kwargs_list:
            assert len(type_and_kwargs) == 2, ('invalid writer: %s'
                                               % type_and_kwargs)
            type, kwargs = type_and_kwargs
            writers.append(self._get_writer(type, kwargs))
        return writers

    def _get_writer(self, type, kwargs):
        # TODO reuse writers?
        if type == 'writepls':
            writer = WritePls(**kwargs)
        elif type == 'writeplsx':
            writer = WritePlsx(**kwargs)
        # TODO Add a writer for a single global file per run. Should return
        # same instance for each "dir" arg.
        self._writers.append(writer)
        return writer

    def flush_all(self):
        for writer in self._writers:
            writer.flush()

class _WriteBase:
    def __init__(self, dir):
        self._dir = dir

    # Mocked in tests.
    def _open(self, filename, log):
        try:
            file = open(filename, 'w')
            log.info('opened %s for writing' % filename)
        except:
            log.fatal('failed to open %s for writing: %s'
                      % (filename, sys.exc_info()) )
            exit()
        return file

    # Mocked in tests.
    def _close(self, file):
        file.close()

# Write a single file containing all streams found at the seed.
class WritePls(_WriteBase):
    # Write "streams" to "filename" (and flush by close()-ing).
    def write(self, filename, streams, log):
        # TODO make sure filename is relative
        abs_filename = os.path.join(self._dir, filename + '.pls')
        file = self._open(abs_filename, log)
        file.write('[playlist]\n')
        index = 0
        for stream in streams:
            if not (stream.has_key('file') and stream.has_key('title')):
                # Incomplete streams should never make it this far.
                log.error('incomplete: %s' % stream)
                continue
            index += 1
            file.write('File%i=%s\nTitle%i=%s\n'
                      % (index, stream['file'], index, stream['title']))
        file.write('NumberOfEntries=%i\n' % len(streams))
        file.write('Version=2\n')
        self._close(file)

    # Our write() already flushes.
    def flush(self):
        pass

# Writes one .plsx file per stream.
class WritePlsx(_WriteBase):
    # TODO crop filenames_used to reasonable length
    # TODO crop common prefix from filenames?
    # TODO make sure subdir is relative
    # Write "streams" to files in "subdir" (and flush by close()-ing each).
    def write(self, subdir, streams, log):
        filenames_used = []  # Ensure unique names.
        for stream in streams:
            if not (stream.has_key('file') and stream.has_key('title')):
                # Incomplete streams should never make it this far.
                log.error('incomplete: %s' % stream)
                continue
            out_dir_abs = os.path.join(self._dir, subdir)
            self._mkdir_p(out_dir_abs)
            filename = os.path.join(out_dir_abs,
                                    utils.sanitize_filename(stream['title']) +
                                        '.plsx')
            filename = utils.get_unique_filename(filename, filenames_used)
            filenames_used.append(filename)
            file = self._open(filename, log)
            file.write('File1=%s\nTitle1=%s\n'
                       % (stream['file'], stream['title']))
            self._close(file)

    # Mocked in tests.
    def _mkdir_p(self, dir):
        utils.mkdir_p(dir)

    # Our write() already flushes.
    def flush(self):
        pass
